/***************************************************************************
 创建者: 华磊
 开始时间: 2020.8.14
 copyright: (C) 华友高科
 修改说明: (每次有修改就添加一条，带有 修改人，修改时间，修改描述)
 example (1) hualei 2020.5.8 类的具体实现代码编写

 ***************************************************************************
 *  @file x.h
 *  功能:
 *
 *                                                                         *
 ***************************************************************************/
#ifndef ECATMASTERIGH_H
#define ECATMASTERIGH_H

#include "ecatmasterbase.h"
#include <QQueue>
#include <QVector>
#include <QDebug>
#include "domparser.h"
#include "ecatbusxml.h"
#include "GeneralDefine.h"
#include "measuretime.h"
#include "ethercaterror.h"
#include <ecrt.h>
#include "robotbase.h"

/**
 * @brief The EcatMasterIgh class igh接口
 */
class EcatMasterIgh : public EcatMasterBase
{
public:
    EcatMasterIgh(int pthread_priority_in, int pthread_schedule_in);
    ~EcatMasterIgh();

public:
    int getEthercatDebugInfo(EthercatDebugInfo& debugInfo);
    int getEthercatSlavesInformation(std::vector<EcatBusDevInfo_gsoap>& slavesInfo );
    int setAlias(int node, unsigned short alias);
    int sdoUpload(int node
                  ,int rObIndex
                  ,int rObSubIndex
                  ,LONG64 &rData
                  ,int &rDataLen);
    int sdoDownload(int node
                    , int wObIndex
                    , int wObSubIndex
                    , LONG64 wData
                    , int wDataLen);


protected:
    void masterBootStrap(){}
    void masterError();
    void masterInit();
    void masterPreOp();
    void masterSafeOp();
    void masterOp();
    int checkTimeMaxLimit();


    void dcMethod1();


    /**
     * @brief addMsg  , 添加消息反馈
     */
    void addMsg( int messageLevel,
                 std::string componentName,
                 std::string messageType,
                 int messageCode,
                 int robotId,
                 int parameter1 = 0,
                 int parameter2 = 0,
                 int parameter3 = 0,
                 int parameter4 = 0 );

//    bool sdoRealtimeWrite( ec_sdo_request_t *pSdoRequest, int pos,  int v , int byteNum, int offset );
//    bool sdoRealtimeRead( ec_sdo_request_t *pSdoRequest,  int pos, void *val , int byteNum, int offset );



private:

    /**
         * @brief updateDomainData //读写过程数据 (帧数据交互)
         */
    void updateDomainData();//hualei todo ,cost time 1679us.
    void readMotorData(RobotBase *rob);
    void readIoData(RobotBase *rob);
    int exchangeData_EncoderReceiver();
    int initialSdo_EncoderReceiver(int &aliasOut,int &sdoIndexOut);
    void writeMotorData(RobotBase *rob);
    void writeIoData(RobotBase *rob);
    void writeTestData(RobotBase *rob);

    int downloadServoSdoConfig(int &aliasOut, int &sdoIndexOut);
    int downloadIodeviceSdoConfig(int &aliasOut, int &sdoIndexOut);
    void sync_distributed_clocks(void);
    void update_master_clock(void);
    void update_master_clock_hualei(void);


    /**
     * @brief displayEthercatConfig //打印从站配置
     * @param nd
     */
    void displayEthercatConfig( int nd );

    /**
     * @brief displayDomainRegConfig //打印域数据寄存器信息
     */
    void displayDomainRegConfig( );



    /**
     * @brief displayBusDevicesInfo //打印总线设备信息
     */
    void displayBusDevicesInfo();

    /**
     * @brief getBusSlaveConfig //读取已经使用设备的ethercat配置信息
     * @return
     */
    bool getBusSlavePdoConfig();

    /**
     * @brief getEcatDeviceConfig //获取从站配置,(仅io模块)
     * @param node
     * @return
     */
    int getEcatIoPdoConfig_byCode(S_EcatDevInfo &devicePdoInfo, uint32_t vendor,
                                  uint32_t productCodeIn);
    int getEcatIoPdoConfig_xml(S_EcatDevInfo &devicePdoInfo, QString xmlFilePath);
    int getEcatDeviceConfig_byEeprom(S_EcatDevInfo &devicePdoInfoOut, int nodeIn);
    int getEcatIoDeviceConfig(S_EcatDevInfo &devicePdoInfo, int node);
    int getIoDevicePdoConfigByCode(S_EcatDevInfo &devicePdoInfo, int node);
    int getEcatMotorPdoConfig(S_EcatDevInfo &devicePdoInfo);

    /**
     * @brief slaveConfig  //初始化设备(写配置 pdo ,sdo ,reg等)
     * @return
     */
    bool initialBusSlavesPdoConfig();

    /**
     * @brief activeMaster  //激活主站,调用后需要等待一小段时间（1ms以上），才能收发数据，不然会导致死机。
     * @return
     */
    bool activeMaster();

    /**
     * @brief syncsConfig //SM同步配置
     * @param sc
     * @param nd
     */
    int syncsConfig(ec_slave_config_t *&sc, int nd);

    /**
     * @brief entriesConfig //配置对象字典寄存器
     * @param nd
     */
    int entryRegConfig(int nd);
    int entryRegConfig_motor(int nd, S_EcatDevInfo* info);
    int entryRegConfig_ioModule(int nd,S_EcatDevInfo* info);
    int entryRegConfig_EncoderReceiver(int nd,S_EcatDevInfo* info);
    int getIoModuleDiDoSize(int nd, S_EcatDevInfo* info, int &diSize, int &diBitOffset, int &doSize,
                            int &doBitOffset, int &aiSizeOut, int &aoSizeOut, int &encoderSizeOut, int &controlSizeOut, int &statusSizeOut);
    int getIoModuleDiDoSize_default(S_EcatDevInfo* info, int &diSize, int &diBitOffset, int &doSize,
                     int &doBitOffset, int &aiSizeOut, int &aoSizeOut, int &encoderSizeOut, int &controlSizeOut, int &statusSizeOut);
    //配置不对会导致coredump
    int assignPdoDomainOffset(int nd, S_EcatDevInfo* info, int diBitOffset, int doBitOffset,EcatIo* io);
    int assignPdoDomainOffset_default(int nd, S_EcatDevInfo* info, int diBitOffset, int doBitOffset,EcatIo* io);

    /**
     * @brief sdosConfig //sdo注册 (每个厂商的sdo定义是不一样的)
     * @param nd
     */
    void initialMotorSdo(int nd);


    /**
        * @brief getResultFromSystemCall  获取控制台命令返回
        * @param pCmd  写入控制台命令
        * @param pResult 返回数据
        * @param size  读取返回长度charbm5mZiIscXE
        * @return
        */
    int getResultFromSystemCall(const char* pCmd, char* pResult, int size);

    /**
        * @brief regRealtimeRead   实时读寄存器数据
        * @param pRegRequest
        * @param pos
        * @param v
        * @param byteNum
        * @param regadr
        * @return
        */
    bool regRealtimeRead( ec_reg_request_t *pRegRequest, int pos, void *val , int byteNum, int regadr );

    /**
        * @brief regRealtimeWrite  实时写寄存器数据
        * @param pRegRequest
        * @param pos
        * @param v
        * @param byteNum
        * @param regadr
        * @return
        */
    bool regRealtimeWrite( ec_reg_request_t *pRegRequest, int pos, void *val , int byteNum, int regadr );

    /**
         * @brief sdoRealtimeRead SDO方式读取数据
         * @param pSdoRequest SDO资源申请的指针
         * @param pos 节点
         * @param v 读到的值
         * @param byteNum 读几个字节的数
         * @param offset
         * @return true if ok
         */
    bool sdoRealtimeRead( ec_sdo_request_t *pSdoRequest,
                          int pos, void *val , int byteNum, int offset );

    /**
        * @brief sdoRealtimeWrite     函数功能：在实时运行时进行SDO的数据获取
        * @param pSdoRequest       pSdoRequest:SDO请求指针
        * @param pos     pos:节点位置
        * @param v       出口参数:v:获取的数值
        * @param byteNum      byteNum:请求读取的字节数
        * @param offset       offset:获取数据的偏移
        * @return        返回值： 判断是否获取成功
        */
    bool sdoRealtimeWrite( ec_sdo_request_t *pSdoRequest, int pos, int v, int byteNum, int offset );

    /**
         * @brief rt_check_master_state,检查主站状态
         */
    int rt_check_master_state();
    int rt_check_slaves_state(bool isInitialState);

    /**
         * @brief rt_check_domain_state  :检查数据域状态
         * @return   ，返回值：0=ok
         */
    int rt_check_domain_state();


private:
    MeasureTime* timeTest_1;
    MeasureTime* timeTest_2;
    MeasureTime* timeTest_3;
    MeasureTime* timeTest_4;
    MeasureTime* timeTest_5;
    MeasureTime* timeTest_6;




    int check_error_delay;
    int error_flag_count;

    struct timespec t1,t2,t3,t4;//test timer
    int counter;//test timer

    /**
     * @brief error_flag  从站错误标志
     */
    int error_flag;

    /**
     * @brief master ///主站master
     */
    ec_master_t *master;

    /**
     * @brief domain ///一个结构体域的指针
     */
    ec_domain_t *domain;

    /**
     * @brief domain_p ///域数据的指针
     */
    quint8 *domain_p;

    /**
     * @brief domainOffKeep  ///域的偏移记录   bit 没起作用
     */
    uint domainOffKeep_noUsed;

    /**
     * @brief offCntKeep ///偏移数记录
     */
    uint currentEntryRegIndex;

    /**
     * @brief entriesCount ///对象字典总数
     */
    int entriesCount;
    /**
         * @brief pdoEntryRegList 注册每个对象字典需要的信息, size > entriesCount. pdo偏移通过共享ethercatPdoDataOffsetInfo指针。
         *     //must be lager thean entriesCount
         */
    QVector<ec_pdo_entry_reg_t> pdoEntryRegList;

    /**
     * @brief pAliasSetRegRequest //别名寄存器空间请求
     */
    QVector<ec_reg_request_t *> pAliasSetRegRequest;
    QVector<ec_sdo_request_t *> sdo_request_603f;
    QVector<ec_sdo_request_t *> sdo_request_alias;
    QVector<ec_slave_config_t *> slave_sc;

    /**
     * @brief master_state //主站的状态
     */
    ec_master_state_t master_state;

    /**
     * @brief domain_state  //域的状态
     */
    ec_domain_state_t domain_state;

    /**
     * @brief wakeupTime //app时间
     */
    struct timespec appTime;

    /**
     * @brief cycle_counter  //循环计数
     */
    int cycle_counter;

    /**
     * @brief sync_ref_counter //同步参考计数
     */
    unsigned int sync_ref_counter;

    /**
     * @brief slaveConfigError ///初始化配置失败
     */
    int slaveConfigError;

    /**
     * @brief domainStateRrror ///域数据读写失败， 0=ok, 网线拔了也会报这个错误
     */
    int domainStateRrror;

    /**
     * @brief domain_working_counter // 数据没被从站读取计数
     */
    int   slave_not_read_counter;

    QVector<bool> isSlaveInOp;
    int slavesAl[128];

    bool method2FirstTimeFlag;
    int wkc_lost_max;

    E_ETHERCAT_STAGE stage;
    int wkc_count;
    int wkc_state;

//    uint32_t refTime_old;
    uint32_t refTime;
    uint64_t rerfSumTime;
    uint64_t pcSumTime;
    uint64_t pcCycleCount;
    QQueue<int> wkcRecordQueue;
    int dcAdjustWaitCount;
    int refClockFailedCount;

//updatadomain

};

#endif // ECATMASTERIGH_H
